/* eslint-disable no-underscore-dangle */
/* eslint-disable no-param-reassign */
import { useCallback, useEffect, useState, useRef, useLayoutEffect } from 'react';
import { getOrgTree, getOrgColorMap } from '@/pages/Organization/OrgFlow/services';
import { cloneDeep, flatMap, groupBy, keyBy } from 'lodash';
import * as d3 from 'd3';
import { message } from 'antd';
import useLocalStorage from 'react-use/lib/useLocalStorage';
import { useMount } from 'react-use';
import { useRequest } from '@/hooks';

const ID_KEY = 'organizationPath';
const PID_KEY = 'parentOrganizationPath';
const ORIENTATION = {
    VERTICAL: 'vertical',
    HORIZONTAL: 'horizontal'
};

const useOrgTree = ({ initData, attachData }) => {
    const [user] = useLocalStorage('user');
    const [loading, setLoading] = useState(false);
    const [orientation, setOrientation] = useState(ORIENTATION.VERTICAL);
    const [arrayData, setArrayData] = useState(initData?.length ? [...initData] : null);
    const [treeData, setTreeData] = useState(); // 图形视图要使用的数据
    const [submitData, setSubmitData] = useState(attachData?.length ? [...attachData] : []); // 要提交的数据, 有附加数据的时候使用附加数据
    const [firstLoad, setFirstLoad] = useState(true);
    const userRef = useRef(user);
    const arrayDataRef = useRef(arrayData);
    const submitDataRef = useRef(submitData);
    const { data: orgColorMap } = useRequest(() => getOrgColorMap(), {
        formatResult: res => {
            if (res) {
                const { code, data, msg } = res;
                if (code === 10000) {
                    return keyBy(data, 'organizationCode');
                }
                message.error(msg);
            }
            return undefined;
        }
    });

    // 添加节点
    const addNode = useCallback(
        data => {
            const newSubmit = [
                ...submitDataRef.current,
                {
                    type: 'add',
                    data
                }
            ];
            setSubmitData(newSubmit);
            setArrayData(_combineData(arrayData, newSubmit));
        },
        [arrayData]
    );

    // 删除节点
    const removeNode = useCallback(data => {
        const cloneSubmitData = [...submitDataRef.current];
        const cloneArrayData = [...arrayDataRef.current];
        const recursion = currentData => {
            // 到 arrayData 中找依赖子节点
            const associatedNode = cloneArrayData.filter(
                item => item[PID_KEY] === currentData[ID_KEY] && !item.deleted
            );
            associatedNode.forEach(item => recursion(item));
            // 到 submitData 中找依赖子节点
            const associatedSubmitNode = cloneSubmitData.filter(
                item => item.type === 'add' && item.data[PID_KEY] === currentData[ID_KEY]
            );
            // 先递归删除子节点
            associatedSubmitNode.forEach(item => recursion(item));
            // 判断删除的是否是新添加的节点
            const nodeIndex = cloneSubmitData.findIndex(
                item => item.type === 'add' && item.data[ID_KEY] === (currentData[ID_KEY] || currentData.data[ID_KEY])
            );
            if (nodeIndex > -1) {
                // 从 submitData 中删除记录
                cloneSubmitData.splice(nodeIndex, 1);
                // 删除掉在记录里面的节点
                const arrayNodeIndex = cloneArrayData.findIndex(
                    item => item[ID_KEY] === (currentData[ID_KEY] || currentData.data[ID_KEY])
                );
                if (arrayNodeIndex > -1) {
                    cloneArrayData.splice(arrayNodeIndex, 1);
                }
            } else {
                // 如果是已存在的节点, 就添加删除记录
                cloneSubmitData.push({
                    type: 'delete',
                    data: currentData
                });
                // 修改对应的节点的 deleted
                const targetDataIndex = cloneArrayData.findIndex(item => item[ID_KEY] === currentData[ID_KEY]);
                cloneArrayData[targetDataIndex].deleted = true;
            }
        };
        recursion(data);
        // 保存数据
        setSubmitData(cloneSubmitData);
        setArrayData(cloneArrayData);
    }, []);

    // 折叠左侧节点
    const collapseLeftNode = useCallback((node, collapse) => {
        const result = _collapseSiblingsNode(arrayDataRef.current, node, collapse, 'leftNode');
        setArrayData([...result]);
    }, []);

    // 折叠右侧节点
    const collapseRightNode = useCallback((node, collapse) => {
        const result = _collapseSiblingsNode(arrayDataRef.current, node, collapse, 'rightNode');
        setArrayData([...result]);
    }, []);

    // 折叠所有员工节点
    const collapseAllEmployees = useCallback(() => {
        const cloneArrayData = arrayDataRef.current?.map(item => {
            item.employeeVisible = false;
            return item;
        });
        setArrayData(cloneArrayData);
    }, []);

    // 折叠节点
    const collapseNodes = useCallback((nodes, collapsed = true) => {
        if (nodes) {
            const arr = nodes instanceof Array ? nodes : [nodes];
            arr.forEach(children => {
                const currentChildNode = arrayDataRef.current?.find(item => item[ID_KEY] === children[ID_KEY]);
                if (currentChildNode) {
                    currentChildNode._collapsed = collapsed;
                }
            });
        }
    }, []);

    // 折叠员工数据
    const collapseEmployeesNode = useCallback(
        (node, collapse) => {
            if (node && node.data) {
                // const cloneArrayData =
                //     orientation === ORIENTATION.HORIZONTAL
                //         ? arrayDataRef.current?.map(item => {
                //             item.employeeVisible = false; // 如果是横向模式, 只能展开一个员工节点. 所以要先折叠所有节点
                //             return item;
                //         })
                //         : [...arrayDataRef.current];
                // 2021-2-3 需求变更, 只能展开一个员工节点, 要不然极端情况会出现遮盖
                const cloneArrayData = arrayDataRef.current?.map(item => {
                    item.employeeVisible = false; // 如果是横向模式, 只能展开一个员工节点. 所以要先折叠所有节点
                    return item;
                })
                const currentNode = cloneArrayData.find(item => item[ID_KEY] === node.data[ID_KEY]);
                currentNode.employeeVisible = collapse;

                // 员工节点和子节点只能展开一种. 折叠员工节点, 切换子节点的展开状态
                if (node.parent) {
                    // collapseNodes(node.parent.children.map(item => item.data));
                    // 因为可能存在其他节点的同级子节点会遮盖过来的情况, 所以要一起关闭
                    const collapseSameDepthNodes = data => {
                        let _result = [];
                        if (data?.length) {
                            data.forEach(item => {
                                if (item.depth === node.depth) {
                                    _result.push(item)
                                }
                                if (item.children?.length) {
                                    _result = _result.concat(collapseSameDepthNodes(item.children))
                                }
                            });
                        }
                        return _result
                    }
                    collapseSameDepthNodes([treeData]).forEach(item => {
                        collapseNodes(item.data);
                    });
                } else {
                    currentNode._collapsed = true;
                }
                setArrayData(cloneArrayData);
            }
        },
        [orientation, collapseNodes, treeData]
    );

    // 聚焦任何节点
    const focusNodeOfAny = useCallback(
        targetNodes => {
            setArrayData(_focusNodeOfTheTargetIds(arrayData, targetNodes.map(item => item.data[ID_KEY])));
        },
        [arrayData]
    );

    // 折叠子节点
    // 当前的逻辑很奇怪, 点击折叠符号
    //  如果是折叠的, 就使用"focusNodeOfAny"方式展开子节点,
    //  如果是展开状态, 就递归折叠子节点
    const collapseChildrenNode = useCallback(
        node => {
            if (node && node.data) {
                // 折叠当前节点
                if (!node._collapsed) {
                    focusNodeOfAny([node])
                } else {
                    collapseNodes(node.data, true);
                    // 如果是折叠, 递归折叠子节点的子节点.
                    if (node.children && !node._collapsed) {
                        collapseNodes(node.children.map(item => item.data));
                    }
                }
                // 折叠全部员工节点
                collapseAllEmployees();
                setArrayData([...arrayDataRef.current]);
            }
        },
        [collapseAllEmployees, collapseNodes, focusNodeOfAny]
    );

    // 聚焦当前用户所在的节点的位置
    const focusNodeOfTheCurrentUser = useCallback(
        (visible = false) => {
            let result;
            if (!visible) {
                result = _focusNodeOfTheCurrentUser(arrayData, userRef.current);
            } else {
                // 展开所有节点
                result = arrayData.map(item => {
                    item.hidden = false;
                    item._collapsed = false;
                    item.employeeVisible = false;
                    return item;
                });
            }
            setArrayData(result);
        },
        [arrayData]
    );

    // 切换展示方向
    const toggleOrientation = value => {
        setOrientation(
            value || (orientation === ORIENTATION.HORIZONTAL ? ORIENTATION.VERTICAL : ORIENTATION.HORIZONTAL)
        );
        // 折叠多余的展开的员工节点
        collapseAllEmployees();
    };

    useEffect(() => {
        arrayDataRef.current = arrayData;
    }, [arrayData]);

    useEffect(() => {
        submitDataRef.current = submitData;
    }, [submitData]);

    // mounted
    // 数据源更新后, 重新处理树数据
    useMount(() => {
        // 请求数据
        const fetchData = async () => {
            if (arrayDataRef.current && arrayDataRef.current?.length) {
                return arrayDataRef.current;
            }
            setLoading(true);
            const { data = [], code, msg } = (await getOrgTree()) || {};
            setLoading(false);
            if (code === 10000 && data && data instanceof Array && data.length) {
                return data;
            }
            message.error(msg);
            return null;
        };
        fetchData().then(res => {
            if (!res) {
                return;
            }
            let data;
            data = _cleanData(res);
            data = _combineData(data, submitData);
            data = _injectionPrivateObj(data);
            setArrayData(data);

            // 首次加载, 根据条件聚焦关键节点
            if (data) {
                // 有附加数据的情况属于审批流程, 审批流程要显示修改的节点
                if (attachData) {
                    data = _focusNodeOfTheTargetIds(
                        data,
                        submitData.map(item => item.data[ID_KEY])
                    );
                } else if (userRef.current && userRef.current?.employeeCode) {
                    data = _focusNodeOfTheCurrentUser(data, userRef.current);
                }
                data = _generateTreeData(data);
                if (data && data.id) {
                    data = _mergeCollapseStatus(data);
                    setTreeData(data);
                }
                setFirstLoad(false);
            }
        });
    });

    useLayoutEffect(() => {
        if (arrayData && !firstLoad) {
            let data;
            data = _generateTreeData(arrayData);
            if (data && data.id) {
                data = _mergeCollapseStatus(data);
                setTreeData(data);
            }
        }
    }, [arrayData, firstLoad]);

    return [
        loading,
        treeData,
        submitData,
        orientation,
        toggleOrientation,
        array2Tree,
        addNode,
        removeNode,
        collapseChildrenNode,
        collapseEmployeesNode,
        collapseLeftNode,
        collapseRightNode,
        focusNodeOfTheCurrentUser,
        focusNodeOfAny,
        orgColorMap
    ];
};

// 聚焦当前用户所在的节点的位置
function _focusNodeOfTheCurrentUser(data, userInfo) {
    let result = [...data];
    // 根据当前公司与当前用户, 查找对应节点
    let targetNode = result.find(
        item =>
            // 可能存在这个人在多家公司都有任职, 应该要定位到这个人所在的这家公司的那个节点
            item.organizationCode ===
                (userInfo?.firstOrgInfo?.firstDepartmentCode || userInfo?.firstOrgInfo?.firstCompanyCode) &&
            // 这个员工可能是领导, 要判断
            (item?.employees?.some(employee => employee.employeeCode === userInfo.employeeCode) ||
                item?.leaderEmployees?.some(employee => employee.employeeCode === userInfo.employeeCode))
    );
    if (!targetNode) {
        // 没有节点, 就定位根节点
        targetNode = result.filter(item => item.parentOrganizationPath === '')[0] || null;
    }
    if (targetNode) {
        // 特殊需求, 至少需要展示三层级的节点
        // 所以判断当前用户是不是第二级节点, 如果是就强制展示子节点, 而不是员工节点
        // let forceExpandChildrenNode = false;
        // const rootNode = data.filter(item => item.parentOrganizationPath === '')[0]; // 根节点
        // if (targetNode.parentOrganizationPath === rootNode.organizationPath) { // 判断二级节点
        //     forceExpandChildrenNode = true;
        // }
        result = _focusNodeOfTheTargetIds(data, [targetNode[ID_KEY]]);
        // result = _collapseSiblingsNode(result, targetNode, false, 'leftNode');
        // result = _collapseSiblingsNode(result, targetNode, false, 'rightNode');
        // 当前节点是根节点, 表示是管理员的身份, 展示子节点, 不显示员工列表
        // targetNode.employeeVisible = !forceExpandChildrenNode;
        // targetNode._collapsed = !forceExpandChildrenNode;
        // 如果有子节点就显示子节点, 否则显示员工节点
        if (result.some(item => item.parentOrganizationPath === targetNode.organizationPath)) {
            targetNode.employeeVisible = false;
            targetNode._collapsed = false;
        } else {
            targetNode.employeeVisible = true;
            targetNode._collapsed = true;
        }
        // if (targetNode.organizationType !== 1) {
        //     targetNode.employeeVisible = true;
        //     targetNode._collapsed = true;
        // }
    }
    return result;
}

// 聚焦指定节点(集), 折叠不相干的节点. 审批流程
function _focusNodeOfTheTargetIds(data, targetIds) {
    // 先隐藏所有节点
    const result = data.map(item => {
        item.hidden = true;
        item._collapsed = true;
        item.employeeVisible = false;
        return item;
    });
    let currentId;
    const findParentNode = node => node && node[PID_KEY] && result.find(item => item[ID_KEY] === node[PID_KEY]);
    const findNode = id => result.find(item => item[ID_KEY] === id);
    const checkChildNode = node => result.some(dataItem => dataItem.parentOrganizationPath === node.organizationPath)
    while (targetIds?.length) {
        currentId = targetIds.pop();
        let currentNode = findNode(currentId);
        // 如果有子节点就显示子节点, 否则显示员工节点
        if (!checkChildNode(currentNode)) {
            currentNode.employeeVisible = true;
        }
        while (currentNode) {
            currentNode.hidden = false;
            // 如果有员工节点就展示员工节点
            if (!currentNode.employeeVisible) {
                currentNode._collapsed = false;
            }
            currentNode = findParentNode(currentNode);
        }
    }
    // 判断同级节点是否全是隐藏节点, 如果全是隐藏节点就全显示.
    Object.values(groupBy(result, PID_KEY)).forEach(arr => {
        if (arr.filter(item => !item.hidden).length === 0) {
            arr.forEach(item => {
                item.hidden = false;
            });
        }
    });
    return result;
}

// 折叠左右节点
function _collapseSiblingsNode(allData, data, collapse, direction) {
    const result = [...allData];
    if (data) {
        let currentNode = result.find(item => item[ID_KEY] === data[ID_KEY]);
        while (currentNode && currentNode[direction]) {
            currentNode[direction].hidden = collapse;
            currentNode = currentNode[direction];
        }
    }
    return result;
}

// 清洗数据
function _cleanData(data) {
    let temp = [];
    if (data && data.length) {
        // 删除ID为空的数据
        temp = data.filter(item => !!item[ID_KEY]);
        // 删除掉没有父节点且子节点为空的节点, 避免多根节点
        temp = array2Tree(temp);
        // 如果只有根节点不做查找根节点操作
        if (data.length > 1) {
            temp = temp.filter(item => item[PID_KEY] === '' && item.children && item.children.length);
        }
        temp = _treeToArray(temp);
    }
    return temp;
}

// 排序数据
function _sortData(data) {
    return data.sort((a, b) => a.sort - b.sort);
}

// 合并数据
function _combineData(data, submitData) {
    let newData = [...data];
    submitData.forEach(item => {
        // 检查是否存在节点
        const dataIndex = data.findIndex(currentData => currentData[ID_KEY] === item.data[ID_KEY]);
        if (dataIndex > -1) {
            if (item.type === 'add') {
                newData[dataIndex].append = true;
            }
            if (item.type === 'delete') {
                newData[dataIndex].deleted = true;
            }
        } else if (item.type === 'add') {
            const addData = { ...item.data };
            addData.append = true;
            addData.hidden = false;
            newData.push(addData);
        }
    });
    newData = _sortData(newData);
    newData = _associateSiblingsNode(newData);
    return newData;
}

// 合并 _collapsed 属性
function _mergeCollapseStatus(data) {
    const cloneData = { ...data };
    if (cloneData) {
        // 将维护在 nodeData.data 里的 _collapsed 属性赋值给 nodeData
        cloneData._collapsed = cloneData?.data ? cloneData.data._collapsed : true;
        if (cloneData.children?.length) {
            cloneData.children = cloneData.children.map(child => _mergeCollapseStatus(child));
        }
    }
    return cloneData;
}

// 生成 d3 树需要的数据
function _generateTreeData(data) {
    try {
        const filteredData = _cleanData(data.filter(item => !item.hidden));
        const result = d3
            .stratify()
            .id(d => d[ID_KEY])
            .parentId(d => d[PID_KEY])(filteredData);
        delete result.parent;
        return result;
    } catch (error) {
        console.log('=树解析错误>', error);
        message.error('数据解析错误');
        return null;
    }
}

// 注入新的属性
function _injectionPrivateObj(data) {
    let result;
    result = data.map(item => {
        const temp = item;
        temp.employeeVisible = false; // 员工的显示状态
        temp._collapsed = true; // 折叠状态
        return temp;
    });
    // 默认展开前两级节点
    result = result.map(item => {
        if (item[PID_KEY] === '') {
            item._collapsed = false;
        }
        return item;
    });
    return result;
}

// 关联兄弟节点
function _associateSiblingsNode(data) {
    let result;
    // 遍历每个节点, 附加上一个节点和下一个节点
    result = Object.values(groupBy(data, PID_KEY)).map(siblingNode => {
        const cloneSiblingNode = [...siblingNode];
        for (let i = 0; i < cloneSiblingNode.length; i += 1) {
            cloneSiblingNode[i].leftNode = i === 0 ? null : cloneSiblingNode[i - 1];
            cloneSiblingNode[i].rightNode = i === cloneSiblingNode.length - 1 ? null : cloneSiblingNode[i + 1];
        }
        return cloneSiblingNode;
    });
    result = flatMap(result);
    return result;
}

/**
 * 树数据转换成数组
 * @param data
 * @returns {[]|*[]}
 */
function _treeToArray(data) {
    if (!data || data.length === 0) {
        return [];
    }
    let result = [];
    for (let i = 0; i < data.length; i += 1) {
        const newItem = { ...data[i] };
        if (newItem.children && newItem.children.length) {
            result = result.concat(_treeToArray(newItem.children));
        }
        delete newItem.children;
        result.push(newItem);
    }
    return result;
}

/**
 * 数组转树
 * @param array
 * @returns {[]}
 */
function array2Tree(array) {
    const newArray = cloneDeep(array);
    const result = [];
    const map = {};
    newArray.forEach(item => {
        map[item[ID_KEY]] = item;
    });
    newArray.forEach(item => {
        const parent = map[item[PID_KEY]];
        if (parent) {
            (parent.children || (parent.children = [])).push(item);
        } else {
            result.push(item);
        }
    });
    return result;
}

export default useOrgTree;
